﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using UnityEngine;

public static class ValueExtension
{
    public static float Abs(this float value)
    {
        return Mathf.Abs(value);
    }

    public static Rect Clamp(this Rect minRect, Rect maxRect)
    {
        minRect.xMin = Mathf.Clamp(minRect.xMin, maxRect.xMin, maxRect.xMax);
        minRect.yMin = Mathf.Clamp(minRect.yMin, maxRect.yMin, maxRect.yMax);
        minRect.xMax = Mathf.Clamp(minRect.xMax, maxRect.xMin, maxRect.xMax);
        minRect.yMax = Mathf.Clamp(minRect.yMax, maxRect.yMin, maxRect.yMax);
        return minRect;
    }

    public static Vector4 Clamp01(this Vector4 vector)
    {
        return new Vector4(Mathf.Clamp01(vector.x), Mathf.Clamp01(vector.y), Mathf.Clamp01(vector.z), Mathf.Clamp01(vector.w));
    }

    public static float ClampAngle(this float angle, float min, float max)
    {
        if ((angle < 90f) || (angle > 270f))
        {
            if (angle > 180f)
            {
                angle -= 360f;
            }
            if (max > 180f)
            {
                max -= 360f;
            }
            if (min > 180f)
            {
                min -= 360f;
            }
        }
        angle = Mathf.Clamp(angle, min, max);
        if (angle < 0f)
        {
            angle += 360f;
        }
        return angle;
    }

    public static Vector3 ClampAngle(this Vector3 vec, Vector3 min, Vector3 max)
    {
        return new Vector3(vec.x.ClampAngle(min.x, max.x), vec.y.ClampAngle(min.y, max.y), vec.z.ClampAngle(min.z, max.z));
    }

    public static Vector3 ClampInBounds(this Vector3 pos, Bounds bounds)
    {
        pos.x = Mathf.Clamp(pos.x, bounds.min.x, bounds.max.x);
        pos.y = Mathf.Clamp(pos.y, bounds.min.y, bounds.max.y);
        pos.z = Mathf.Clamp(pos.z, bounds.min.z, bounds.max.z);
        return pos;
    }

    public static Vector3 ClampMagnitude(this Vector3 vec, float min, float max)
    {
        vec = Vector3.ClampMagnitude(vec, max);
        if (vec.magnitude < min)
        {
            vec = (Vector3) (vec.normalized * min);
        }
        return vec;
    }

    public static Vector3 ClampMagnitude(this Vector3 vec, Vector3 min, Vector3 max)
    {
        if (vec.x >= 0f)
        {
            vec.x = Mathf.Clamp(vec.x, min.x, max.x);
        }
        else
        {
            vec.x = Mathf.Clamp(vec.x, -max.x, -min.x);
        }
        if (vec.y >= 0f)
        {
            vec.y = Mathf.Clamp(vec.y, min.y, max.y);
        }
        else
        {
            vec.y = Mathf.Clamp(vec.y, -max.y, -min.y);
        }
        if (vec.z >= 0f)
        {
            vec.z = Mathf.Clamp(vec.z, min.z, max.z);
            return vec;
        }
        vec.z = Mathf.Clamp(vec.z, -max.z, -min.z);
        return vec;
    }

    public static Rect ClampPosition(this Rect originalRect, Rect maxRect)
    {
        Vector2 vector = new Vector2(originalRect.width / 2f, originalRect.height / 2f);
        Vector2 min = maxRect.min + vector;
        Vector2 max = maxRect.max - vector;
        if ((max.x < min.x) || (max.y < min.y))
        {
            Vector2 vector4 = (Vector2) ((min + max) / 2f);
            if (max.x < min.x)
            {
                max.x = vector4.x;
                min.x = vector4.x;
            }
            if (max.y < min.y)
            {
                max.y = vector4.y;
                min.y = vector4.y;
            }
        }
        originalRect.center = originalRect.center.ClampPosition(min, max);
        return originalRect;
    }

    public static Vector2 ClampPosition(this Vector2 pos, Vector2 min, Vector2 max)
    {
        return new Vector2(Mathf.Clamp(pos.x, min.x, max.x), Mathf.Clamp(pos.y, min.y, max.y));
    }

    public static float Closest(this float value, float a, float b)
    {
        return ((Mathf.Abs((float) (a - value)) >= Mathf.Abs((float) (b - value))) ? b : a);
    }

    public static Vector3 Closest(this Vector3 value, Vector3 a, Vector3 b)
    {
        Vector3 vector = a - value;
        Vector3 vector2 = b - value;
        return ((vector.magnitude >= vector2.magnitude) ? b : a);
    }

    public static bool ContainsFlag(this LayerMask layerMask, int layer)
    {
        return ((layerMask.value & (((int) 1) << layer)) != 0);
    }

    public static Vector2 Divide(this Vector2 vec1, Vector2 vec2)
    {
        return new Vector3(vec1.x / vec2.x, vec1.y / vec2.y);
    }

    public static Vector3 Divide(this Vector3 vec1, Vector3 vec2)
    {
        return new Vector3(vec1.x / vec2.x, vec1.y / vec2.y, vec1.z / vec2.z);
    }

    public static string format(this string str, params object[] args)
    {
        return string.Format(str, args);
    }

    public static Vector3 GetBottom(this Bounds bounds)
    {
        return new Vector3(bounds.center.x, bounds.min.y, bounds.center.z);
    }

    public static Vector2 GetBottom(this Rect rect)
    {
        return new Vector2(rect.center.x, rect.yMin);
    }

    public static Vector2 GetExtents(this Rect rect)
    {
        return (Vector2) (rect.size / 2f);
    }

    public static Vector3[] GetFourCorners(this Rect rect)
    {
        return new Vector3[] { rect.min, new Vector2(rect.xMin, rect.yMax), rect.max, new Vector2(rect.xMax, rect.yMin) };
    }

    public static Vector3 GetLeft(this Bounds bounds)
    {
        return new Vector3(bounds.min.x, bounds.center.y, bounds.center.z);
    }

    public static Vector2 GetLeft(this Rect rect)
    {
        return new Vector2(rect.xMin, rect.center.y);
    }

    public static float GetPercentageAlong(this Vector3 pos, Vector3 a, Vector3 b)
    {
        Vector3 vector = b - a;
        Vector3 lhs = pos - a;
        float introduced2 = Vector3.Dot(lhs, vector.normalized);
        return (introduced2 / vector.magnitude);
    }

    public static Vector3 GetRandomPoint(this Bounds bounds)
    {
        return new Vector3 { x = UnityEngine.Random.Range(bounds.min.x, bounds.max.x), y = UnityEngine.Random.Range(bounds.min.y, bounds.max.y), z = UnityEngine.Random.Range(bounds.min.z, bounds.max.z) };
    }

    public static Vector2 GetRandomPoint(this Rect rect)
    {
        return new Vector2 { x = UnityEngine.Random.Range(rect.min.x, rect.max.x), y = UnityEngine.Random.Range(rect.min.y, rect.max.y) };
    }

    public static Vector3 GetRight(this Bounds bounds)
    {
        return new Vector3(bounds.max.x, bounds.center.y, bounds.center.z);
    }

    public static Vector2 GetRight(this Rect rect)
    {
        return new Vector2(rect.xMax, rect.center.y);
    }

    public static Vector3 GetTop(this Bounds bounds)
    {
        return new Vector3(bounds.center.x, bounds.max.y, bounds.center.z);
    }

    public static Vector2 GetTop(this Rect rect)
    {
        return new Vector2(rect.center.x, rect.yMax);
    }

    public static Vector2 GetUV(this Rect rect, Vector2 position)
    {
        Vector2 vector = position - rect.min;
        Vector2 vector2 = rect.max - rect.min;
        float x = vector.x / vector2.x;
        return new Vector2(x, vector.y / vector2.y);
    }

    public static float GetValue(this WrapMode mode, float time, float length)
    {
        if (((mode == WrapMode.Default) || (mode == WrapMode.Once)) || ((mode == WrapMode.Once) || (mode == WrapMode.ClampForever)))
        {
            return Mathf.Clamp(time, 0f, length);
        }
        if (mode == WrapMode.PingPong)
        {
            return Mathf.PingPong(time, length);
        }
        if (mode == WrapMode.Loop)
        {
            return Mathf.Repeat(time, length);
        }
        return 0f;
    }

    public static int Lerp(this int start, int end, float time)
    {
        return Mathf.RoundToInt(Mathf.Lerp((float) start, (float) end, time));
    }

    public static Rect Lerp(this Rect start, Rect end, float time)
    {
        return new Rect(Mathf.Lerp(start.x, end.x, time), Mathf.Lerp(start.y, end.y, time), Mathf.Lerp(start.width, end.width, time), Mathf.Lerp(start.height, end.height, time));
    }

    public static Quaternion LookRotation2D(this Vector2 forward)
    {
        return ((Vector3) forward).LookRotation2D();
    }

    public static Quaternion LookRotation2D(this Vector3 forward)
    {
        if (forward == Vector3.zero)
        {
            return Quaternion.identity;
        }
        Quaternion quaternion = Quaternion.FromToRotation(Vector3.forward, Vector3.left);
        Quaternion quaternion2 = Quaternion.LookRotation(forward) * quaternion;
        if (Mathf.Abs(forward.y) > Mathf.Abs(forward.x))
        {
            quaternion2 = Quaternion.LookRotation(forward, Vector3.right) * quaternion;
        }
        return quaternion2;
    }

    public static Bounds Merge(this IEnumerable<Bounds> bounds)
    {
        Vector3 vector = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
        Vector3 vector2 = new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
        IEnumerator<Bounds> enumerator = bounds.GetEnumerator();
        try
        {
            while (enumerator.MoveNext())
            {
                Bounds current = enumerator.Current;
                vector.x = Mathf.Min(current.min.x, vector.x);
                vector.y = Mathf.Min(current.min.y, vector.y);
                vector.z = Mathf.Min(current.min.z, vector.z);
                vector2.x = Mathf.Max(current.max.x, vector2.x);
                vector2.y = Mathf.Max(current.max.y, vector2.y);
                vector2.z = Mathf.Max(current.max.z, vector2.z);
            }
        }
        finally
        {
            if (enumerator == null)
            {
            }
            enumerator.Dispose();
        }
        return new Bounds { min = vector, max = vector2 };
    }

    public static Rect Merge(this Rect[] rects)
    {
        Vector2 vector = new Vector2(float.PositiveInfinity, float.PositiveInfinity);
        Vector2 vector2 = new Vector2(float.NegativeInfinity, float.NegativeInfinity);
        foreach (Rect rect in rects)
        {
            vector.x = Mathf.Min(rect.xMin, vector.x);
            vector.y = Mathf.Min(rect.yMin, vector.y);
            vector2.x = Mathf.Max(rect.xMax, vector2.x);
            vector2.y = Mathf.Max(rect.yMax, vector2.y);
        }
        return new Rect { min = vector, max = vector2 };
    }

    public static Bounds Multiply(this Bounds bounds, Matrix4x4 matrix)
    {
        Vector3 vector = matrix.MultiplyPoint(bounds.min);
        Vector3 vector2 = matrix.MultiplyPoint(bounds.max);
        Vector3 center = (Vector3) ((vector + vector2) * 0.5f);
        return new Bounds(center, vector2 - vector);
    }

    public static Vector2 Multiply(this Vector2 vec1, Vector2 vec2)
    {
        return new Vector2(vec1.x * vec2.x, vec1.y * vec2.y);
    }

    public static Vector3 Multiply(this Vector3 vec1, Vector3 vec2)
    {
        return new Vector3(vec1.x * vec2.x, vec1.y * vec2.y, vec1.z * vec2.z);
    }

    public static Vector3 Raycast(this Plane plane, Ray ray)
    {
        float num;
        plane.Raycast(ray, out num);
        return ray.GetPoint(num);
    }

    public static Vector3 Remainder(this Vector3 vec1, Vector3 vec2)
    {
        return new Vector3(vec1.x % vec2.x, vec1.y % vec2.y, vec1.z % vec2.z);
    }

    public static Vector3 Round(this Vector3 org)
    {
        return new Vector3(Mathf.Round(org.x), Mathf.Round(org.y), Mathf.Round(org.z));
    }

    public static Bounds Scale(this Bounds bounds, float scale)
    {
        return bounds.Scale(((Vector3) (Vector3.one * scale)));
    }

    public static Bounds Scale(this Bounds bounds, Vector3 scale)
    {
        bounds.center = Vector3.Scale(bounds.center, scale);
        bounds.size = Vector3.Scale(bounds.size, scale);
        return bounds;
    }

    public static Rect Scale(this Rect rect, float scale)
    {
        return rect.Scale(((Vector2) (Vector2.one * scale)));
    }

    public static Rect Scale(this Rect rect, Vector2 scale)
    {
        rect.position = Vector2.Scale(rect.position, scale);
        rect.size = Vector2.Scale(rect.size, scale);
        return rect;
    }

    public static Rect ScaleAroundCenter(this Rect rect, Vector2 scale)
    {
        Vector2 center = rect.center;
        rect.size = Vector2.Scale(rect.size, scale);
        rect.center = center;
        return rect;
    }

    public static Color SetA(this Color org, float a)
    {
        org.a = a;
        return org;
    }

    public static Color SetB(this Color org, float b)
    {
        org.b = b;
        return org;
    }

    public static Rect SetExtents(this Rect rect, Vector2 extents)
    {
        Vector2 center = rect.center;
        rect.size = (Vector2) (extents * 2f);
        rect.center = center;
        return rect;
    }

    public static Color SetG(this Color org, float g)
    {
        org.g = g;
        return org;
    }

    public static Rect SetHeight(this Rect org, float h)
    {
        org.height = h;
        return org;
    }

    public static Color SetR(this Color org, float r)
    {
        org.r = r;
        return org;
    }

    public static Rect SetWidth(this Rect org, float w)
    {
        org.width = w;
        return org;
    }

    public static Rect SetX(this Rect org, float x)
    {
        org.x = x;
        return org;
    }

    public static Vector3 SetX(this Vector3 org, float x)
    {
        org.x = x;
        return org;
    }

    public static Vector3 SetXZ(this Vector3 org, float x, float z)
    {
        org.x = x;
        org.z = z;
        return org;
    }

    public static Rect SetY(this Rect org, float y)
    {
        org.y = y;
        return org;
    }

    public static Vector3 SetY(this Vector3 org, float y)
    {
        org.y = y;
        return org;
    }

    public static Vector3 SetZ(this Vector3 org, float z)
    {
        org.z = z;
        return org;
    }

    public static Rect Shift(this Rect rect, Vector2 offset)
    {
        rect.position += offset;
        return rect;
    }

    public static Vector3 Snap(this Vector3 vector, float gridSize)
    {
        return vector.Snap(((Vector3) (Vector3.one * gridSize)));
    }

    public static Vector3 Snap(this Vector3 vector, Vector3 gridSize)
    {
        if (gridSize.x != 0f)
        {
            vector.x = vector.x.Closest(gridSize.x * Mathf.Floor(vector.x / gridSize.x), gridSize.x * (Mathf.Floor(vector.x / gridSize.x) + 1f));
        }
        if (gridSize.y != 0f)
        {
            vector.y = vector.y.Closest(gridSize.y * Mathf.Floor(vector.y / gridSize.y), gridSize.y * (Mathf.Floor(vector.y / gridSize.y) + 1f));
        }
        if (gridSize.z != 0f)
        {
            vector.z = vector.z.Closest(gridSize.z * Mathf.Floor(vector.z / gridSize.z), gridSize.z * (Mathf.Floor(vector.z / gridSize.z) + 1f));
        }
        return vector;
    }

    public static Rect ToRect(this Bounds bounds)
    {
        return new Rect(bounds.center.x - bounds.extents.x, bounds.center.y - bounds.extents.y, bounds.extents.x * 2f, bounds.extents.y * 2f);
    }

    public static Rect ToRect(this Vector3 min, Vector3 max)
    {
        return new Rect { min = min, max = max };
    }

    public static Rect ToRectXZ(this Bounds bounds)
    {
        return new Rect { size = new Vector2(bounds.size.x, bounds.size.z), center = new Vector2(bounds.center.x, bounds.center.z) };
    }

    public static string ToStringRank(this int value)
    {
        switch (value.ToString().Last<char>())
        {
            case '1':
                return (value + "st");

            case '2':
                return (value + "nd");

            case '3':
                return (value + "rd");
        }
        return (value + "th");
    }
}

